function Collect(conf) {
    console.log("%cCollect online.","color:#fff;background:#4caf50;padding:0 18px");

    conf = conf || {};
    this.type = conf.type;
    this.app = conf.app;
    this.collectFunctions = [];
    this.collectSubjects = {};
    this.appType = conf.appType || "pi";
    this.customData = conf.custom || {};
    this.user_mark = "";
    this.autoClick = conf.autoClick || true;
    this.modConf = conf.modConf || {};
    this.keepCh = Boolean(conf.keepCh);

    var cookies = getCookies();
    this.ent_id = cookies.ent_id || conf.ent_id;

    if (conf.uri) {
        this.uri = labelReplace(conf.uri, conf);
        this.uri2 = this.uri.split('/')
        this.uri2.push(this.uri2.pop().replace(/\./, '2.'))
        this.uri2 = this.uri2.join('/')
    }

    var uuidKey = conf.uuidKey || "user_id";
    this.uuid = cookies[uuidKey];

    if (!this.uuid) {
        var _uuid = storage.getItem("__PI_UUID");
        if (_uuid && !cookies[uuidKey]) {
            this.uuid = _uuid;
        } else {
            this.uuid = uuid("p", conf.useCid);
            if (this.uuid.indexOf("Pi-") !== -1) {
                storage.setItem("__PI_UUID", this.uuid);
            }
        }
    }

}

var CP = Collect.prototype;

/**
 * 添加一个统计类型
 * @param {Function} fn 统计类型模块
 */
CP.add = function(fn) {
    this.collectFunctions.push(fn);
};

/**
 * 生成所有统计类型实例
 * @return {Undefined} 无返回值
 */
CP.execute = function() {
    var funcId;
    for(var i = 0;i < this.collectFunctions.length;i++) {
        var subject = new this.collectFunctions[i](this);
        this.collectSubjects[subject.name] = subject;
    }
    this.ready = true;
    var item;
    while(waiting4Send.length) {
        item = waiting4Send.pop();
        sendCollect.call(this, item[0], item[1]);
    }
    item = null;
}

/**
 * 处理 ch
 * @return {String} ch 名称
 */
CP.handlCh = function() {
    var ch = getQuery("ch") || "";
    var chCookieKey = "__ch__";
    var gCh = "";
    if (window.sessionStorage) {
        gCh = window.sessionStorage.getItem(chCookieKey) || "";
    }
    if (ch) {
        if (this.keepCh && gCh !== ch && window.sessionStorage) {
            window.sessionStorage.setItem(chCookieKey, ch);
        }
    } else {
        if (this.keepCh && gCh) {
            ch = gCh;
        }
    }
    return ch;
}

/**
 * 获取用户环境信息
 * @return {Object} 信息对象
 */
CP.getUser = function() {
    var winScreen = window.screen;
    // 获取地址上的 ch 参数
    var ch = this.handlCh();
    var prev_ch = "";
    var prevSearch;
    if (document.referrer) {
        // 有 referrer 的时候尝试获取上面的 ch
        // referrer 的 ch 视为上游渠道标识
        prevSearch = document.referrer.split("?");
        prevSearch = prevSearch[1] || "";
        if (prevSearch) {
            prev_ch = getQuery("ch", prevSearch);
        }
    }

    return {
        "ua":window.navigator.userAgent
        ,"screen_width":winScreen.availWidth
        ,"screen_height":winScreen.availHeight
        ,"pixel_depth":winScreen.pixelDepth
        ,"screen":winScreen.availWidth+"x"+winScreen.availHeight
        ,"referer":document.referrer
        ,"uid":this.uuid
        ,"ent_id":this.ent_id
        ,"app_type": this.appType
        ,"domain": document.domain
        ,"user_mark": this.user_mark
        ,"device": osAndDevice.device
        ,"os": osAndDevice.os
        ,"os_version": osAndDevice.osVersion
        ,"pf": osAndDevice.pf
        ,"pf_version": osAndDevice.pfVersion
        ,"ch": ch
        ,"prev_ch": prev_ch
    };
};

/**
 * 获取自定义数据
 * @return {Object} 自定义数据
 */
CP.getCustom = function() {
    return extend({}, this.customData);
}

/**
 * 设置一个自定义数据字段
 * @param  {String} key 数据字段
 * @param  {Mix}    val 字段值
 * @return {Mix}        设置后的字段值
 */
CP.setCustom = function(key, val) {
    if (key) {
        this.customData[key] = val;
    }
    return this.customData[key];
}

var waiting4Send = [];

/**
 * 发送统计数据
 * @param  {Mix}       data 统计数据
 * @param  {String}    type 统计类型
 * @return {Undefined}      无返回值
 */
function sendCollect(data, type) {
    if (!this.ready) {
        waiting4Send.push([data, type]);
        return;
    }
    sendRequest.call(this, data, type, this.uri)
    sendRequest.call(this, data, type, this.uri2)
}

function sendRequest(data, type, uri) {
    var subjectData = this.collectSubjects[type] && this.collectSubjects[type].report() || {};
    data = extend({}, subjectData, data);

    var img = new Image();

    img.onload = function(){
        img.onload = null;
        img.onerror = null;
        img = null;
    };
    img.onerror = function(){
        img.onload = null;
        img.onerror = null;
        img = null;
    };

    if (uri) {
        if (uri.indexOf("?") === -1) {
            uri += "?";
        }
        if (isObject(data)) {
            if (!data["_"]){
                data["_"] = (new Date()).getTime()+"."+rand(8);
            }
            uri += toParam(data);
        } else {
            uri += data;
        }
    } else {
        uri = "/collect";
        if (data && type) {
            uri += "/"+type+"?";
            if (isObject(data)) {
                if (!data["_"]){
                    data["_"] = (new Date()).getTime()+"."+rand(8);
                }
                uri += toParam(data);
            } else {
                uri += data;
            }
        } else {
            uri += "?cd="+data;
        }
    }

    uri = uri.split('/')
    uri.push(Date.now(), uri.pop())
    uri = uri.join('/')

    img.src = uri;
}

/**
 * 发送所有模块的统计数据
 * @return {Undefined} 无返回值
 */
CP.report = function() {
    var data = {
        "user":this.getUser()
        ,"type":this.type
        ,"t":(new Date()).getTime()
    };
    for(var n in this.collectSubjects) {
        if (this.collectSubjects.hasOwnProperty(n) && this.collectSubjects[n] && typeof(this.collectSubjects[n].report) === "function") {
            data[n] = this.collectSubjects[n].report();
        }
    }
    data = encodeURIComponent(JSON.stringify(data));

    sendCollect.call(this,data);
};

/**
 * 发送指定类型的统计数据
 * @param  {String}    type 统计类型
 * @param  {Object}    data 统计数据
 * @return {Undefined}      无返回值
 */
CP.send = function(type, data, cattype){
    if(!type){
        console.warn("[type] undefined.");
        return;
    }
    if (!cattype) {
        cattype = type;
    }
    var dat = this.getUser();
    dat.client_type = this.type;
    dat.app = this.app;
    dat.log_type = type;
    dat = extend(dat, this.getCustom(), data);
    sendCollect.call(this, dat, cattype);
};

// 简化别名
CP.pv = function(data){
    data = data || {};
    this.send("pageview",data);
}
CP.click = function(data){
    data = data || {};
    this.send("click",data);
}
CP.event = function(data){
    data = data || {};
    this.send("event",data);
}
CP.setUrl = function(url) {
    var collectSubjects = this.collectSubjects
    if (collectSubjects.hasOwnProperty('unload')) {
        collectSubjects['unload'].url = url
    }
}

CP.update = function(key, val) {
    if (isString(key) && hasOwn.call(this, key)) {
        this[key] = val;
    }

    if (isObject(key)) {
        var me = this;
        each(key, function(val, key){
            if (hasOwn.call(me, key)) {
                me[key] = val;
            }
        });
    }
};

var clientCollect = new Collect(window.__PI_COLLECT_CONF || {});
window.PI_COLLECT = clientCollect;
